﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ImageConverter {
  /// <summary>
  /// 图像处理
  /// </summary>
  public static class DealWithImage {
    /// <summary>
    /// 图像图像灰度化
    /// </summary>
    /// <!--将彩色图像转化成为灰度图像的过程成为图像的灰度化处理。彩色图像中的每个像素的颜色有R、G、B三个分量决定，而每个分量有255中值可取，这样一个像素点可以有1600多万（255*255*255）的颜色的变化范围。而灰度图像是R、G、B三个分量相同的一种特殊的彩色图像，其一个像素点的变化范围为255种，所以在数字图像处理种一般先将各种格式的图像转变成灰度图像以使后续的图像的计算量变得少一些。灰度图像的描述与彩色图像一样仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征。图像的灰度化处理可用两种方法来实现。-->
    /// <!-- 第一种方法使求出每个像素点的R、G、B三个分量的平均值，然后将这个平均值赋予给这个像素的三个分量。-->
    /// <!-- 第二种方法是根据YUV的颜色空间中，Y的分量的物理意义是点的亮度，由该值反映亮度等级，根据RGB和YUV颜色空间的变化关系可建立亮度Y与R、G、B三个颜色分量的对应：Y=0.3R+0.59G+0.11B，以这个亮度值表达图像的灰度值。-->
    /// <param name="bitmap"></param>
    /// <returns></returns>
    public static Bitmap ToGray(this Bitmap bitmap) {
      var w = bitmap.Width;
      var h = bitmap.Height;
      for(int i = 0; i < w; i++) {
        for(int j = 0; j < h; j++) {
          // 获取该点的像素的RGB的颜色
          var color = bitmap.GetPixel(i, j);
          // 利用公式计算灰度值 
          var gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
          var newColor = Color.FromArgb(gray, gray, gray);
          bitmap.SetPixel(i, j, newColor);
        }
      }
      return bitmap;
    }

    /// <summary>
    /// 图像灰度反转
    /// </summary>
    /// <!--把每个像素点的R、G、B三个分量的值0的设为255，255的设为0。-->
    /// <param name="bitmap"></param>
    /// <returns></returns>
    public static Bitmap GrayReverse(Bitmap bitmap) {
      var w = bitmap.Width;
      var h = bitmap.Height;

      for(int i = 0; i < w; i++) {
        for(int j = 0; j < h; j++) {
          // 获取该点的像素的RGB的颜色
          var color = bitmap.GetPixel(i, j);
          var newColor = Color.FromArgb(255 - color.R, 255 - color.G, 255 - color.B);
          bitmap.SetPixel(i, j, newColor);
        }
      }
      return bitmap;
    }

    /// <summary>
    /// 图像二值化1：取图片的平均灰度作为阈值，低于该值的全都为0，高于该值的全都为255
    /// </summary>
    /// <param name="bitmap"></param>
    /// <returns></returns>
    public static Bitmap GrayImageBinaryzation1(Bitmap bitmap) {
      var w = bitmap.Width;
      var h = bitmap.Height;
      var average = 0;

      for(int i = 0; i < w; i++) {
        for(int j = 0; j < h; j++) {
          var color = bitmap.GetPixel(i, j);
          average += color.B;
        }
      }
      average = average / (w * h);

      for(int i = 0; i < w; i++) {
        for(int j = 0; j < h; j++) {
          //获取该点的像素的RGB的颜色
          var color = bitmap.GetPixel(i, j);
          int value = 255 - color.B;
          var newColor = value > average ? Color.FromArgb(0, 0, 0) : Color.FromArgb(255,

            255, 255);
          bitmap.SetPixel(i, j, newColor);
        }
      }
      return bitmap;
    }
    /// <summary>
    ///  图像二值化2
    /// </summary>
    /// <param name="bitmap"></param>
    /// <returns></returns>
    public static Bitmap GrayImageBinaryzation2(Bitmap bitmap) {
      int w = bitmap.Width;
      int h = bitmap.Height;
      var bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed);
      var data = bmp.LockBits(new Rectangle(0, 0, w, h),
                              ImageLockMode.ReadWrite,
                              PixelFormat.Format1bppIndexed);

      for(int y = 0; y < h; y++) {
        byte[] scan = new byte[(w + 7) / 8];
        for(int x = 0; x < w; x++) {
          var c = bitmap.GetPixel(x, y);
          if(c.GetBrightness() >= 0.5) scan[x / 8] |= (byte)(0x80 >> (x % 8));
        }
        Marshal.Copy(scan, 0, (IntPtr)((int)data.Scan0 + data.Stride * y), scan.Length);
      }

      return bmp;
    }

  }
}
